﻿
Imports System.IO
Imports System.Threading
Imports osi.root.connector

Public Class dispose_ptr(Of T)
    Inherits pointer(Of T)

    Private Shared ReadOnly default_disposer As Action(Of T)
    Public Event dispose_exception(ByVal ex As Exception)
    Private ReadOnly disposer As Action(Of T) = Nothing
    Private d As Boolean

    Shared Sub New()
        If GetType(T).inherit(GetType(Stream)) Then
            default_disposer = Sub(x As T)
                                   Dim s As Stream = Nothing
                                   s = cast(Of Stream)(x)
                                   k_assert(Not s Is Nothing)
                                   s.Flush()
                                   s.Close()
                                   s.Dispose()
                               End Sub
        ElseIf GetType(T).implement(GetType(IDisposable)) Then
            default_disposer = Sub(x As T)
                                   cast(Of IDisposable)(x).Dispose()
                               End Sub
        ElseIf GetType(T).inherit(GetType(WaitHandle)) Then
            default_disposer = Sub(x As T)
                                   cast(Of WaitHandle)(x).Close()
                               End Sub
        End If
    End Sub

    Public Sub New(ByVal p As Func(Of T),
                   Optional ByVal init As Action = Nothing,
                   Optional ByVal disposer As Action(Of T) = Nothing)
        If Not init Is Nothing Then
            init()
        End If
        If Not p Is Nothing Then
            [set](p())
        End If
        If disposer Is Nothing Then
            k_assert(Not default_disposer Is Nothing)
            Me.disposer = default_disposer
        Else
            Me.disposer = disposer
        End If
    End Sub

    Public Sub New(ByVal p As T,
                   Optional ByVal init As Action = Nothing,
                   Optional ByVal disposer As Action(Of T) = Nothing)
        Me.New(Function() p, init, disposer)
    End Sub

    Public Sub New(Optional ByVal init As Action = Nothing,
                   Optional ByVal disposer As Action(Of T) = Nothing)
        Me.New(DirectCast(Nothing, Func(Of T)), init, disposer)
    End Sub

    Private Sub dispose_instance()
        If Not d Then
            Try
                k_assert(Not disposer Is Nothing)
                If Not empty() Then
                    disposer([get]())
                End If
            Catch ex As Exception
                RaiseEvent dispose_exception(ex)
            End Try
            d = True
        End If
    End Sub

    Protected Sub dispose()
        dispose_instance()
    End Sub

    Protected Sub queue_dispose()
        k_queue_in_managed_threadpool(AddressOf dispose_instance)
    End Sub

    Public Function disposed() As Boolean
        Return d
    End Function
End Class
